package repository

import (
	"context"
	"intelli-dl-online-logo-go/model"
	"intelli-dl-online-logo-go/utils"

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo"
)

type UserRepository interface {
	Create(ctx context.Context, user *model.User) (*model.User, error)
	GetByID(ctx context.Context, id primitive.ObjectID) (*model.User, error)
	Update(ctx context.Context, id primitive.ObjectID, user *model.User) (*model.User, error)
	Delete(ctx context.Context, id primitive.ObjectID) error
	FindByRole(ctx context.Context, role int) ([]*model.User, error)
	FindByUsername(ctx context.Context, username string) (*model.User, error)
	FindByEmail(ctx context.Context, email string) (*model.User, error)
}

type userRepository struct {
	collection *mongo.Collection
}

func NewUserRepository() UserRepository {
	return &userRepository{
		collection: utils.GetMongoCollection("intelli_dl_online_logo_dev", "users"),
	}
}

func NewUserRepositoryImpl(db *mongo.Database) UserRepository {
	return &userRepository{
		collection: db.Collection("users"),
	}
}

func (ur *userRepository) Create(ctx context.Context, user *model.User) (*model.User, error) {
	result, err := ur.collection.InsertOne(ctx, user)
	if err != nil {
		return nil, err
	}

	user.ID = result.InsertedID.(primitive.ObjectID)
	return user, nil
}

func (ur *userRepository) GetByID(ctx context.Context, id primitive.ObjectID) (*model.User, error) {
	var user model.User
	err := ur.collection.FindOne(ctx, bson.M{"_id": id}).Decode(&user)
	if err != nil {
		return nil, err
	}

	return &user, nil
}

func (ur *userRepository) Update(ctx context.Context, id primitive.ObjectID, user *model.User) (*model.User, error) {
	_, err := ur.collection.UpdateOne(ctx, bson.M{"_id": id}, bson.M{"$set": user})
	if err != nil {
		return nil, err
	}

	return ur.GetByID(ctx, id)
}

func (ur *userRepository) Delete(ctx context.Context, id primitive.ObjectID) error {
	_, err := ur.collection.DeleteOne(ctx, bson.M{"_id": id})
	return err
}

func (ur *userRepository) FindByRole(ctx context.Context, role int) ([]*model.User, error) {
	cursor, err := ur.collection.Find(ctx, bson.M{"role": role})
	if err != nil {
		return nil, err
	}

	var users []*model.User
	if err = cursor.All(ctx, &users); err != nil {
		return nil, err
	}

	return users, nil
}

// FindByUsername 根据用户名查找用户
func (ur *userRepository) FindByUsername(ctx context.Context, username string) (*model.User, error) {
	var user model.User
	err := ur.collection.FindOne(ctx, bson.M{"username": username}).Decode(&user)
	if err != nil {
		return nil, err
	}

	return &user, nil
}

// FindByEmail 根据邮箱查找用户
func (ur *userRepository) FindByEmail(ctx context.Context, email string) (*model.User, error) {
	var user model.User
	err := ur.collection.FindOne(ctx, bson.M{"email": email}).Decode(&user)
	if err != nil {
		return nil, err
	}

	return &user, nil
}
